package ws.performancetest.tests.thread;

import ws.performancetest.api.AbstractTestSuite;
import ws.performancetest.api.annotation.PerformanceTest;
import ws.performancetest.api.exception.TestSuiteSetupException;

/**
 * Test of synchronization mechanisms using a single thread.
 *
 * The purpose is to record the access time for each mechanism.
 * 
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public class SingleThreadTest extends AbstractTestSuite {

  /** Object to obtain lock. */
  private static Synchronization sync = new Synchronization();

  public SingleThreadTest() throws TestSuiteSetupException {
    scriptname = "singleThread.sql";
    // cycleCount = Number of times the thread will try to obtain object lock (number of cycle repetitions).
  }

  /** Test of the synchronized method for a single thread. */
  @PerformanceTest
  public void testSynchronizedMethod() throws InterruptedException {
    Thread t = new Thread(new Runnable() {

      public void run() {
        long t_start, t_finish;
        t_start = System.nanoTime();
        for (int i = 0; i < cycleCount; ++i) {
          sync.synchronizedMethod();
        }
        t_finish = System.nanoTime();
        addLog("SynchronizedMethod", (t_finish - t_start) / cycleCount);
      }
    });
    t.start();
    t.join();
  }

  /** Test of the synchronized block for a single thread. */
  @PerformanceTest
  public void testSynchronizedBlock() throws InterruptedException {
    Thread t = new Thread(new Runnable() {

      public void run() {
        long t_start, t_finish;
        t_start = System.nanoTime();
        for (int i = 0; i < cycleCount; ++i) {
          sync.synchronizedBlock();
        }
        t_finish = System.nanoTime();
        addLog("SynchronizedBlock", (t_finish - t_start) / cycleCount);
      }
    });
    t.start();
    t.join();
  }

  /** Test of the ReentrantLock's lock for a single thread. */
  @PerformanceTest
  public void testLock() throws InterruptedException {
    Thread t = new Thread(new Runnable() {

      public void run() {
        long t_start, t_finish;
        t_start = System.nanoTime();
        for (int i = 0; i < cycleCount; ++i) {

          sync.lock();
        }
        t_finish = System.nanoTime();
        addLog("ReentrantLock", (t_finish - t_start) / cycleCount);
      }
    });
    t.start();
    t.join();
  }

  /** Test of the ReentrantReadWriteLock's read lock for a single thread. */
  @PerformanceTest
  public void testReadLock() throws InterruptedException {
    Thread t = new Thread(new Runnable() {

      public void run() {
        long t_start, t_finish;
        t_start = System.nanoTime();
        for (int i = 0; i < cycleCount; ++i) {
          sync.readLock();
        }
        t_finish = System.nanoTime();
        addLog("ReadLock", (t_finish - t_start) / cycleCount);
      }
    });
    t.start();
    t.join();
  }

  /** Test of the ReentrantReadWriteLock's write lock for a single thread. */
  @PerformanceTest
  public void testWriteLock() throws InterruptedException {
    Thread t = new Thread(new Runnable() {

      public void run() {
        long t_start, t_finish;
        t_start = System.nanoTime();
        for (int i = 0; i < cycleCount; ++i) {
          sync.writeLock();
        }
        t_finish = System.nanoTime();
        addLog("WriteLock", (t_finish - t_start) / cycleCount);
      }
    });
    t.start();
    t.join();
  }

  /** Test of the Semaphore lock for a single thread. */
  @PerformanceTest
  public void testSemaphore() throws InterruptedException {
    Thread t = new Thread(new Runnable() {

      public void run() {
        long t_start, t_finish;
        t_start = System.nanoTime();
        try {
          for (int i = 0; i < cycleCount; ++i) {
            sync.semaphore();
          }          
        } catch (InterruptedException ex) {
          ex.printStackTrace();
          System.exit(1);
        }
        t_finish = System.nanoTime();
        addLog("Semaphore", (t_finish - t_start) / cycleCount);
      }
    });
    t.start();
    t.join();
  }

  public static void main(String[] args) throws Exception {
    new SingleThreadTest().runAllTests();

//    File script = new File(scriptname);
//    /* erase previous results. */
//    script.delete();
//    Desktop desktop = Desktop.getDesktop();
//    desktop.open(script);
  }
}
